//!
/**
 ***********************************************************************************************************
 * <RBStream Implementation>
 ***********************************************************************************************************
 * @file RBStream.cpp
 ***********************************************************************************************************/

/***********************************************************************************************************
 * Precompiled Header
 ***********************************************************************************************************/
#include "RBMainPCH.h"

/***********************************************************************************************************
 * Includes
 ***********************************************************************************************************/
#include "RBStream.h"

#include "RBComponent.h"
#include "RBEntity.h"
#include "RBRTTIRegister.h"
#include "RBStreamReader.h"

/***********************************************************************************************************
 * Defines
 ***********************************************************************************************************/

/***********************************************************************************************************
 * Classes implementation
 ***********************************************************************************************************/
RBStream::RBObjectMap RBStream::ms_mCreators;
std::set<RBStreamReader*> RBStream::ms_sReaders;

static RBRTTIRegister ms_Init;

/***********************************************************************************************************
 *
 ***********************************************************************************************************/
void RBStream::WriteRTTI(const RBRTTI* pRTTI, RBObject* pObject)
{
    uint32 uiID = m_mRegisteredObjects[pObject];
    Write(uiID);
    Write(pRTTI->GetName());
}

/***********************************************************************************************************
 *
 ***********************************************************************************************************/
RBObject* RBStream::CreateObject()
{
    uint32 uiID;
    Read(uiID);
    RBString strRTTI;
    Read(strRTTI);

    RBObject* pObject = CreateObject(strRTTI);
    RegisterPointer(pObject, uiID);

    return pObject;
}

/***********************************************************************************************************
 *
 ***********************************************************************************************************/
void RBStream::RegisterRTTI(const RBString& strRTTI, CreateFunction createFunc)
{
    ms_mCreators[strRTTI] = createFunc;
}

/***********************************************************************************************************
 *
 ***********************************************************************************************************/
RBObject* RBStream::CreateObject(const RBString& strRTTI)
{
    RBObjectMap::iterator iter = ms_mCreators.find(strRTTI);
    if (iter == ms_mCreators.end())
    {
        RBAssert(false, "Cound not find Creation for object");
        return NULL;
    }
    return (iter->second)(*this);
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
template<>
void RBStream::Write(const RBString* pStr, uint32 uiCount)
{
    for (uint32 ui=0; ui < uiCount; ++ui)
    {
        const char* pcBuffer = pStr[ui].c_str();
        uint32 uiLen = static_cast<uint32>(pStr[ui].size());
        Write(uiLen);
        WriteBuffer(pcBuffer, uiLen);
    }
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
template <>
void RBStream::Read(RBString* pStr, uint32 uiCount)
{
    for (uint32 ui=0; ui < uiCount; ++ui)
    {
        uint32 uiLen;
        Read(uiLen);
        char* pcBuffer = new char[uiLen+1];
        ReadBuffer(pcBuffer, uiLen);
        pcBuffer[uiLen] = 0;
        pStr[ui] = pcBuffer;
        delete[] pcBuffer;
    }
}

/***********************************************************************************************************
 *
 ***********************************************************************************************************/
void RBStream::RegisterPointer(void* pObject, uint32 uiID)
{
    m_mRegisteredObjects[pObject] = uiID;
    m_mRegisteredIDs[uiID] = pObject;
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
RBStream& RBStream::operator=( const RBStream& )
{
    RBAssert(false, "Assignements on RBStreams is forbidden");
    return *this;
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
void RBStream::Serialize(RBStream::SerializeMode eMode)
{
    m_bWrite = (eMode == SM_WRITE);
#pragma TODO("Replug fucking serialization")
#if 0
    RBRegisterVisitor kRegister(*this);
    // Register all inserted objects when we are writing
    uint32 uiTopObjectCount = m_vTopObjects.size();
    if (IsWriting())
    {
        for (uint32 ui=0; ui < uiTopObjectCount; ++ui)
        {
            RBEntity& entity = RBEntity::Get(m_vTopObjects[ui]);
            uint16 partCount = entity.GetPartCount();
            for (RBEntityPartHandle partIdx=0; partIdx < partCount; ++partIdx)
            {
                RBEntityPart& part = entity.GetPart(partIdx);
                uint32 componentCount = part.GetComponentCount();
                for (uint32 uiComponent=0; uiComponent<componentCount; ++uiComponent)
                {
                    part.GetComponent<RBComponent>()->Serialize();
                }
            }
            m_vTopObjects[ui]->Accept(kRegister);
        }
    }

    // Write RTTI to stream for registered objects / Create and register object
    uint32 uiObjectCount = IsReading() ? 0 : m_vObjectsRegistered.size();
    *this & uiObjectCount;

    for (uint32 ui=0; ui < uiObjectCount; ++ui)
    {
        if (IsWriting())
        {
            m_vObjectsRegistered[ui]->SerializeRTTI(*this);
        }
        else
        {
            CreateObject();
        }
    }

    // Write / Find all top objects in the same order
    *this & uiTopObjectCount;
    if (IsReading())
    {
        m_vTopObjects.resize(uiTopObjectCount);
    }
    for (uint32 ui=0; ui < uiTopObjectCount; ++ui)
    {
        Link(m_vTopObjects[ui]);
    }

    // Serialize data
    for (uint32 ui=0; ui < uiObjectCount; ++ui)
    {
        if (m_vObjectsRegistered[ui])
        {
            m_vObjectsRegistered[ui]->Serialize(*this);
        }
    }
#endif
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
void RBStream::Insert( RBEntityHandle entity )
{
    m_vTopObjects.push_back(entity);
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
RBEntityHandle RBStream::GetObjectAt( uint32 ui )
{
    return m_vTopObjects[ui];
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
uint32 RBStream::GetObjectCount() const
{
    return m_vTopObjects.size();
}

/************************************************************************************************************
 * 
 ************************************************************************************************************/
void RBStream::RegisterReader( RBStreamReader* pReader )
{
    ms_sReaders.insert(pReader);
}

/************************************************************************************************************
 * 
 ************************************************************************************************************/
void RBStream::UnregisterReader( RBStreamReader* pReader )
{
    ms_sReaders.erase(pReader);
}

/************************************************************************************************************
 * 
 ************************************************************************************************************/
void RBStream::ClearReaders()
{
    std::set<RBStreamReader*>::iterator iter = ms_sReaders.begin();
    for (; iter != ms_sReaders.end(); ++iter)
    {
        delete *iter;
    }
    ms_sReaders.clear();
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
RBStream* RBStream::Load( const RBString& strFilename )
{
    bool bLoadSuccessful = false;
    std::set<RBStreamReader*>::iterator iter = ms_sReaders.begin();
    RBStream* pStream = 0;
    for (; iter != ms_sReaders.end() && !bLoadSuccessful; ++iter)
    {
        RBStreamReader* pReader = *iter;
        if (pReader && ((pStream = pReader->Load(strFilename)) != NULL))
        {
            bLoadSuccessful = true;
        }
    }

    if (bLoadSuccessful)
    {
    }

    return pStream;
}